
/**
 * @file	main.cpp
 * @author  Alessandro Carrega <contact@alexcarrega.com>
 * @version 2.0
 * @secion LICENSE
 *
 * This file is part of graph_max_flow.
 *
 * graph_max_flow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * graph_max_flow is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with graph_max_flow.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
 
#define ERROR_PARAM 1 			  ///< valore di ritorno del programma in caso di parametro errato
#define ERROR_INPUT_FILE 2		  ///< valore di ritorno del programma nel caso sia impossibile leggere dal file di input 
#define ERROR_INPUT_FILE_FORMAT 3 ///< valore di ritorno del programma in caso di formato non correto del file di input
#define ERROR_SOURCE_NOT_DEFINED 4 ///< valore di ritorno del programma in caso di nodo source non definito
#define ERROR_SINK_NOT_DEFINED 5 ///< valore di ritorno del programma in caso di nodo sink non definito

#include <string.h>
#include <vector>
#include <fstream>
#include <iostream>

using namespace std;

#include "flow_network.h"

/**
 * \brief Il programma carica il grafo dal file di input e calcola il flusso massimo tra i nodo \p source e \p sink.
 * \param argc numero di parametri (compreso il nome del programma)
 * \param argv vettore di dimensione \p argc contenente i vari parametri. Il primo elemento è il nomo del programma.
 * 
 * \par Sintatti corretta:
 * graph_max_flow &lt;input_file&gt;
 */
int main(int argc, char *argv[]) {
	// Se il numero dei parametri è diverso da 2 visualizza un messaggio di errore e termina il programma
	if (argc != 2) {
		cerr << "ERROR: number of params not correct." << endl;
		cerr << "USAGE: " << argv[0] << " <input_file>" << endl;
		return ERROR_PARAM;
	}
	
	// Il file di input è in \p argv[1]
	char *input_filename = argv[1];
	ifstream input_stream(input_filename);
	if (!input_stream.good()) { // Se non è possibile leggere il file visualizza un messaggio di errore e termina il programma
		cerr << "ERROR: not possibile to read the file " << input_filename << endl;
		return ERROR_INPUT_FILE;
	}
	
	char c, type;
	char str[100];
	bool error = false;
	int num_node = 0, num_edge = 0, node;
	int source = 0, sink = 0;
	int u, v, cap;
	FlowNetwork *flow_network;
	
	// Legge fino alla fine del file
	while (!input_stream.eof()) {
		input_stream >> c; // leggo il primo caratterere di ogni riga
		switch (c) {
		// Commento: ignoro tutta la riga
		case 'c':
			while (!input_stream.eof() && input_stream.get() != '\n');
			break;
		// Definizione del problema: leggo il numero di nodi e di edge
		case 'p':
			input_stream >> str >> num_node >> num_edge;
			if (strcmp(str, "max")) // se non è presente max dopo p significa formato errato
				error = true;
			else // altrimenti inizializza FlowNetwork.
			{
				flow_network = new FlowNetwork(num_node, num_edge);
			}
			break;
		// Nuovi speciali: legge i nodi source e sink
		case 'n':
			input_stream >> node >> type;
			switch (type)
			{
			// Nodo source
			case 's':
				source = node;
				break;
			// Nodo sink
			case 't':
				sink = node;
				break;
			}
			break;
		// Nuovo edge: legge i nodi del'edge e la capacità
		case 'a':
			// Se non è il numero di edge e di nodi non posso aggiungere un edge
			if (num_edge == 0 || num_node == 0)
				error = true;
			else {
				input_stream >> u >> v >> cap;
				// Aggiunge un nuovo edge a FlowNetwork.
				flow_network->add_edge(u, v, cap);
			}
			break;
		// Se l'inizio della riga è diverso allora il formato non è corretto
		default:
			error = true;
		}
		
		// Se error = TRUE significa che il formato non è corretto
		if (error) {
			cerr << "ERROR: input file " << input_filename << " not correct" << endl;
			return ERROR_INPUT_FILE_FORMAT;
		}
	}
	
	if (source == 0)
	{
		cerr << "ERROR: nodo source not defined in input_file " << input_filename << endl;
		return ERROR_SOURCE_NOT_DEFINED;
	}
	
	if (sink == 0)
	{
		cerr << "ERROR: nodo sink not defined in input_file " << input_filename << endl;
		return ERROR_SINK_NOT_DEFINED;
	}
	
	// Stampa a video il flusso massimo
	cout << flow_network->max_flow(source, sink) << endl;
	
	return 0;
}
